package com.leaves.service.impl;

import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.leaves.common.constant.RedisConstant;
import com.leaves.common.constant.TokenConstant;
import com.leaves.common.publicmethod.methods.UserInfoDeal;
import com.leaves.common.publicmethod.entity.PageEntity;
import com.leaves.common.util.AesCbcUtil;
import com.leaves.common.util.RegexUtil;
import com.leaves.entity.UserInfo;
import com.leaves.entity.dto.AddUserInfoDto;
import com.leaves.entity.dto.DisableUser;
import com.leaves.entity.dto.LoginUser;
import com.leaves.entity.vo.UserInfoVo;
import com.leaves.exception.MessageCenterException;
import com.leaves.mapper.AuthInfoMapper;
import com.leaves.mapper.RoleInfoMapper;
import com.leaves.response.ApiResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import com.leaves.mapper.UserInfoMapper;
import com.leaves.service.UserInfoService;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author: LEAVES
 * @Version 1.0
 * @Date: 2021年09月21日 13时14分00秒
 * @Description:
 */
@Slf4j
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

    @Resource
    private RoleInfoMapper roleInfoMapper;
    @Resource
    private AuthInfoMapper authInfoMapper;
    @Resource
    private UserInfoDeal userInfoDeal;

    @Override
    public void createVerifyCode(HttpServletResponse response) {
        LineCaptcha captcha = CaptchaUtil.createLineCaptcha(120, 30, 4, 20);
//        captcha.setGenerator(new MathGenerator());
        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            captcha.write(outputStream);
            String code = captcha.getCode();
            code = code.toLowerCase();
            response.setHeader("verify", code);
            response.setHeader("Pragma", "No-cache");
            response.setHeader("Cache-Control", "no-cache");
            response.setDateHeader("Expires", 0);
            //将验证码存入redis中
            SaManager.getSaTokenDao().set(RedisConstant.CODE + code, code, RedisConstant.CODE_EXPIRATION);
//            response.setHeader("code", captcha.getImageBase64());
        } catch (IOException e) {
            e.printStackTrace();
            log.error(" ##IO流异常## ");
            new MessageCenterException("验证码获取失败");
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    log.error(" ##流关闭异常## ");
                    new MessageCenterException("验证码获取失败");
                }
            }
        }
    }

    @Override
    public ApiResult loginCheck(LoginUser loginUser, HttpServletResponse response) {
        String code = loginUser.getCode().toLowerCase();
        code = SaManager.getSaTokenDao().get(RedisConstant.CODE + code);
        if (ObjectUtil.isNull(code)) {
            throw new MessageCenterException("验证码错误");
        }

        //解析密码
        String pwd = AesCbcUtil.decode(loginUser.getPassword());
        if (StringUtils.isBlank(pwd)) {
            throw new MessageCenterException("数据解密失败");
        }
        System.out.println("pwd = " + pwd);
        if (!RegexUtil.regexPassword(pwd)) {
            throw new MessageCenterException("密码必须为6-18位且至少包含大小写字母和数字的组合字符");
        }
        //加密密码
        String password = AesCbcUtil.encrypt(pwd);
        System.out.println("password = " + password);
        if (StringUtils.isBlank(password)) {
            throw new MessageCenterException("数据加密失败");
        }
        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.eq(ObjectUtil.isNotNull(password), "password", password)
                .eq(true, "enable", 1);
        if (RegexUtil.regexMobilePhone(loginUser.getUsername())) {
            wrapper.eq(ObjectUtil.isNotNull(loginUser.getUsername()), "phone", loginUser.getUsername());
        } else {
            wrapper.eq(ObjectUtil.isNotNull(loginUser.getUsername()), "username", loginUser.getUsername());
        }
        //根据账号/手机号码和密码查询用户信息
        UserInfo userInfo = this.getOne(wrapper);
        System.out.println("userInfo = " + userInfo);
        if (ObjectUtil.isNull(userInfo)) {
            return ApiResult.error("账号或密码错误");
        }
        if (userInfo.getEnable() == 2) {
            return ApiResult.error("账号已被禁用，请联系管理员");
        }
        UserInfoVo userInfoVo = userInfoDeal.getUserInfo(userInfo);
        //判断用户登录类型
        if (loginUser.getDevice().equals(TokenConstant.APP)) {

        } else if (loginUser.getDevice().equals(TokenConstant.WEB)) {

        } else {
            throw new MessageCenterException("登录类型错误");
        }
        StpUtil.login(userInfo.getId(), new SaLoginModel()
                        .setDevice(loginUser.getDevice())                // 此次登录的客户端设备标识, 用于[同端互斥登录]时指定此次登录的设备名称
                        .setIsLastingCookie(false)        // 是否为持久Cookie（临时Cookie在浏览器关闭时会自动删除，持久Cookie在重新打开后依然存在）
                //.setTimeout(60 * 60 * 24 * 7)    // 指定此次登录token的有效期, 单位:秒 （如未指定，自动取全局配置的timeout值）
                //.setToken("") // 预定此次登录的生成的Token
        );
        userInfoVo.setDevice(loginUser.getDevice());
        Map<String, Object> map = new HashMap<>();
        map.put("userInfo", userInfoVo);
        final String token = StpUtil.getTokenValueByLoginId(userInfo.getId());
        map.put(TokenConstant.AUTHORIZATION, StpUtil.getTokenValueByLoginId(userInfo.getId()));
        response.setHeader(TokenConstant.AUTHORIZATION, token);
        return ApiResult.success("登录成功", map);
    }

    @Override
    public ApiResult getCurrentAccountInformation() {
        //获取当前账号登录ID
        String loginId = StpUtil.getLoginIdAsString();
        //获取当前账号登录设备
        String loginDevice = StpUtil.getLoginDevice();
        UserInfoVo userInfoVo = userInfoDeal.getUserInfo(loginId);
        userInfoVo.setDevice(loginDevice);
        return ApiResult.successData(userInfoVo);
    }

    /**
     * 分页查询
     *
     * @param pageEntity
     * @return
     */
    @Override
    public ApiResult pageQueryUserInfoList(PageEntity pageEntity) {
        PageHelper.startPage(pageEntity.getPageNumber(), pageEntity.getPageSize());
        List<UserInfoVo> userInfoList = this.baseMapper.selectListAll();
        userInfoList.forEach(x -> {
            userInfoDeal.getUserInfo(x);
        });
        PageInfo<UserInfoVo> pageInfo = new PageInfo<>(userInfoList);
        return ApiResult.successData(pageInfo);
    }

    /**
     * 账号封禁
     *
     * @param disableUser
     * @return
     */
    @Transactional
    @Override
    public ApiResult disableUserInfo(DisableUser disableUser) {
        // 先踢下线
        StpUtil.kickout(disableUser.getUserId());
        // 封禁指定账号
        StpUtil.disable(disableUser.getUserId(), disableUser.getDisableTime());
        //更新数据库
        long disableTime = StpUtil.getDisableTime(disableUser.getUserId());
        LocalDateTime localDateTime = LocalDateTimeUtil.offset(LocalDateTime.now(), disableTime, ChronoUnit.SECONDS);
        Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
        UserInfo userInfo = new UserInfo();
        userInfo.setId(disableUser.getUserId());
        userInfo.setEnable(2);
        userInfo.setDisableTime(date);
        this.updateById(userInfo);
        return ApiResult.success();
    }

    /**
     * 手动解封账号
     *
     * @param userId
     * @return
     */
    @Override
    public ApiResult untieDisableUserInfo(String userId) {
        // 解禁指定账号
        StpUtil.untieDisable(userId);
        //更新数据库
        UserInfo userInfo = new UserInfo();
        userInfo.setId(userId);
        userInfo.setEnable(1);
        this.updateById(userInfo);
        return ApiResult.success();
    }

    /**
     * 新增账号信息
     *
     * @param addUserInfoDto
     * @return
     */
    @Override
    public ApiResult AddUserInfoDto(AddUserInfoDto addUserInfoDto) {

        UserInfo userInfo = this.getOne(new QueryWrapper<UserInfo>().lambda()
                .eq(true, UserInfo::getUsername, addUserInfoDto.getUsername()));
//        if (ObjectUtil.isNotEmpty(userInfo)){
//            throw new MessageCenterException("账号已存在");
//        }
//        try {
//            String pwd = AESEncrypt.AESEncrypt(addUserInfoDto.getPassword());
//            userInfo = this.getOne(new QueryWrapper<UserInfo>().lambda()
//                    .eq(true, UserInfo::getUsername, addUserInfoDto.getUsername())
//                    .eq(true, UserInfo::getPassword, password));
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
        return null;
    }
}
